﻿using Microsoft.SharePoint;
using Microsoft.SharePoint.Utilities;
using Microsoft.SharePoint.WebControls;
using SP.Exporters;
using SP.ListItem.WordExporter.Utils;
using System;
using System.Globalization;
using System.IO;
using System.Text.RegularExpressions;
using System.Web;

namespace SP.ListItem.WordExporter.Layouts
{
    public partial class WordExporter : LayoutsPageBase
    {
        #region Properties
        public Guid ListId
        {
            get
            {
                var listIdEncoded = Request.QueryString["ListId"];
                var listIdDecoded = SPHttpUtility.UrlKeyValueDecode(listIdEncoded);
                Guid result;
                Guid.TryParse(listIdDecoded, out result);
                return result;
            }
        }
        public int ListItemId
        {
            get
            {
                var itemId = Request.QueryString["ItemId"];
                int result;
                int.TryParse(itemId, out result);
                return result;
            }
        }
        #endregion

        protected void Page_Load(object sender, EventArgs e)
        {
            try
            {
                string exportFileName;
                var exportStream = GenerateExportStream(out exportFileName);
                WriteFileToResponse(exportStream, exportFileName);
            }
            catch (ExporterException ex)
            {
                ErrorLbl.Text = ex.Message;
            }
        }

        /// <summary>
        /// Generates the export stream for the specified query string parameters.
        /// </summary>
        /// <param name="exportFileName">Name of the export file.</param>
        /// <returns></returns>
        /// <exception cref="WordExporterException">
        /// Source list was not found
        /// or
        /// </exception>
        protected Stream GenerateExportStream(out string exportFileName)
        {
            Stream exportStream;
            using (var site = new SPSite(SPContext.Current.Site.ID))
            using (var web = site.OpenWeb(SPContext.Current.Web.ID))
            using (var rootWeb = site.OpenWeb(site.RootWeb.ID))
            {
                SPList sourceList;
                try
                {
                    sourceList = web.Lists[ListId];
                }
                catch (ArgumentException ex)
                {
                    throw new WordExporterException("Source list was not found", ex);
                }
                SPFile templateFile;
                try
                {
                    templateFile = web.GetWordExporterTemplateFile(sourceList.Title);
                }
                catch (WordExporterException)
                {
                    // also look in the root web
                    templateFile = rootWeb.GetWordExporterTemplateFile(sourceList.Title);
                }
                SPListItem listItem;
                try
                {
                    listItem = sourceList.GetItemByIdAllFields(ListItemId);
                }
                catch (ArgumentException ex)
                {
                    throw new WordExporterException(
                        String.Format(CultureInfo.InvariantCulture, "No item with id {0} was found in site {1} for list {2}",
                                      ListItemId, web.Url, sourceList.Title), ex);
                }
                exportStream = listItem.GenerateWordExportFile(templateFile);
                var rgx = new Regex("[^a-zA-Z0-9]");
                exportFileName = String.Format(CultureInfo.InvariantCulture, "WordExport_{0}_{1:dd_MM_yyyy_hh_mm}",
                                               rgx.Replace(listItem.Title, "_"), DateTime.Now);
            }
            return exportStream;
        }

        /// <summary>
        /// Writes the file to response.
        /// </summary>
        /// <param name="stream">The stream.</param>
        /// <param name="fileName">Name of the file.</param>
        protected void WriteFileToResponse(Stream stream, string fileName)
        {
            var response = Page.Response;
            response.Clear();

            var binaryReader = new BinaryReader(stream);
            try
            {
                response.ClearHeaders();
                response.ClearContent();
                response.AddHeader("Accept-Ranges", "bytes");
                response.Buffer = false;
                var fileLength = stream.Length;

                response.AddHeader("Content-Length", fileLength.ToString(CultureInfo.InvariantCulture));
                response.AddHeader("Content-Range", string.Format(" bytes {0}-{1}/{2}", 0, fileLength - 1, fileLength));
                response.AddHeader("Connection", "Keep-Alive");

                response.ContentType = "application/ms-word";
                response.AddHeader("Content-Disposition", "attachment;filename=" + HttpUtility.UrlEncode(fileName + ".docx", System.Text.Encoding.UTF8));

                binaryReader.BaseStream.Seek(0, SeekOrigin.Begin);

                if (response.IsClientConnected)
                {
                    response.BinaryWrite(binaryReader.ReadBytes((int)fileLength));
                }
            }
            finally
            {
                binaryReader.Close();
            }
            response.End();
        }
    }
}
